#pragma once
#include <memory>
#include "Socket.hpp"
#include "Log.hpp"
#include <poll.h>
// poll

const static int gdefault_port = 8888;
const static int gdefault_backlog = 16;
const static int num = 128;

class PollServer
{
public:
    PollServer(int16_t port = gdefault_port)
        : _port(port), _listensock(std::make_unique<TcpSocket>()), _isruning(false), _rfds(nullptr)
    {
    }
    void Init()
    {
        _listensock->BuildListenSocketMethod(_port, gdefault_backlog);
        _rfds = new struct pollfd[num];
        for (int i = 0; i < num; i++)
        {
            _rfds[i].fd = -1;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }
        _rfds[0].fd = _listensock->GetSockFd();
        _rfds[0].events |= POLLIN; // 关心读事件
    }
    void Loop()
    {
        _isruning = true;
        while (_isruning)
        {
            // 直接获取链接吗？？？？Accept获取连接本质也是等 + 获取，所有我们将他托管到poll上来等
            // fd_set rfds; // 今天我们的server只关心读事件
            // FD_ZERO(&rfds);
            // 根据_array_sock来重置rfds
            // struct timeval timeout = {4, 0}; // 阻塞 + 非阻塞
            // struct timeval timeout = {0, 0};//非阻塞
            int timeout = 0; // 毫秒为单位   { > 0 : 非阻塞 + 阻塞, == 0 : 非阻塞,  == -1 : 阻塞}
            // nullptr 阻塞
            PrintDebug(); //poll不用每一次进行参数的重新设置，输入输出参数分离
            int r = poll(_rfds, num, timeout);
            if (r > 0)
            {
                lg(Info, "poll success, begin event handler");
                EventDistribution();
            }
            else if (r == 0)
            {
                lg(Info, "poll timeout...");
            }
            else
            {
                lg(Error, "poll error !!!!");
                Stop();
            }
            sleep(1);
        }
        _isruning = false;
    }
    void Stop()
    {
        _isruning = false;
    }
    ~PollServer()
    {
    }
    void PrintDebug()
    {
        std::cout << "rfds : ";
        for (int i = 0; i < num; i++)
        {
            if (_rfds[i].fd != -1)
            {
                std::cout << _rfds[i].fd << "  ";
            }
        }
        std::cout << "\n";
    }

private:
    void EventDistribution()
    {
        for (int i = 0; i < num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;
            int fd = _rfds[i].fd;
            if (_rfds[i].revents & POLLIN) // 判断fd是否就绪
            {
                // 判断是普通读事件还是获取连接
                if (fd == _listensock->GetSockFd())
                {
                    std::string clientip;
                    uint16_t port;
                    int sock_fd = _listensock->AcceptSocketOrDie(&clientip, &port); // 这里一定是不需要等待的，只需要直接获取连接
                    if (sock_fd == -1)
                        continue;
                    lg(Info, "get a new link, client info : %s:%d   fd : %d", clientip.c_str(), port, sock_fd);
                    // fd添加到数组中托管
                    int pos = 0;
                    for (; pos < num; pos++)
                    {
                        if (_rfds[pos].fd == -1)
                        {
                            _rfds[pos].fd = sock_fd;
                            _rfds[pos].events = POLLIN;
                            break;
                        }
                    }
                    // 说明已经达到poll管理文件描述符的上线
                    if (pos == num)
                    {
                        // 策略：1.直接关闭 2.扩容
                        close(sock_fd);
                        lg(Info, "poll full!!!");
                    }
                }
                else // 普通fd
                {
                    // 普通的读事件就绪
                    // 读数据是有问题的
                    // 这一次读取不会被卡住吗？ 协议问题
                    char buff[1024];
                    ssize_t n = read(fd, buff, sizeof(buff) - 1);
                    if (n > 0)
                    {
                        buff[n] = 0;
                        std::cout << "client say# " << buff << std::endl;
                        std::string message = "你好呀 PollServer!!! ";
                        message += buff;
                        send(fd, message.c_str(), message.size(), 0);
                        message.clear();
                    }
                    else
                    {
                        lg(Warning, "client quit, maybe close or error, close fd : %d", fd);
                        close(fd);
                        _rfds[i].fd = -1;
                        _rfds[i].events = 0;
                        _rfds[i].revents = 0;
                    }
                }
            }
        }
    }

private:
    std::unique_ptr<Socket> _listensock;
    int16_t _port;
    bool _isruning;

    struct pollfd *_rfds;
};